package com.uxsino.rule.nms.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.uxsino.commons.enums.AlertOrigin;
import com.uxsino.commons.model.BaseNeClass;
// import com.uxsino.commons.model.RunStatus;
import com.uxsino.commons.utils.CopyBeanUtils;
import com.uxsino.rule.model.CompareType;
import com.uxsino.rule.nms.model.AnalysisResult;
import com.uxsino.rule.nms.model.NmsCaller;
import com.uxsino.rule.nms.model.NmsReport;
import com.uxsino.rule.nms.model.SubRuleReport;
import com.uxsino.rule.nms.service.CommandInterpreter;
import com.uxsino.rule.nms.strategy.dto.IndicatorTableDto;
import com.uxsino.rule.nms.strategy.dto.RuleDto;
import com.uxsino.rule.nms.strategy.dto.ValidateAlertInfo;
import com.uxsino.rule.nms.strategy.dto.ValidateMsg;
import com.uxsino.rule.nms.strategy.model.CompositionSupport;

import lombok.Data;
import lombok.EqualsAndHashCode;

import org.apache.commons.lang3.StringUtils;
import org.mvel2.MVEL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.Map.Entry;

/**
 * 
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class CompositionStrategyHandler extends ExtendStrategy {

    private static Logger LOG = LoggerFactory.getLogger(CompositionStrategyHandler.class);

    /**
     * Default constructor
     */
    public CompositionStrategyHandler() {
    }

    public CompositionStrategyHandler(NmsCaller caller) {
        this.callData = caller;
    }

    /**
     * 匹配校验逻辑并返回校验结果
     *
     * @param setting
     * @param value
     */
    @Override
    public boolean ruleMatch(JSONObject setting, String... value) {
        return false;
    }

    /**
     * 根据设置生成阈值范围描述
     *
     * @param setting
     * @return
     */
    @Override
    public String createAlertRange(JSONObject setting) {
        return null;
    }

    public boolean ruleMatch(Map<String, SubRuleReport> subStrategyMap, String simpleFormula) {
        Map<String, Object> param = new HashMap<>();
        for (Entry<String, SubRuleReport> entry : subStrategyMap.entrySet()) {
            param.put(entry.getKey(), entry.getValue().getAlertStatus());
        }
        boolean result = (boolean) MVEL.eval(simpleFormula, param);
        return result;
    }

    /*
     * @Override public NmsReport holisticVerifyProcess() { RuleDto rule =
     * callData.getRule(); ValidateMsg msg = getMsg(); List<String> componentIds =
     * getComponentIds(rule);
     * msg.setComponentId(componentIds.stream().distinct().collect(Collectors.
     * joining(","))); IndicatorTableDto indDto = callData.getIndicator(); boolean
     * alertStatus = false; List<ValidateAlertInfo> alertInfoList = new
     * ArrayList<>(); for (Object obj : JSON.parseArray(rule.getSettings())) {
     * JSONObject setting = JSON.parseObject(obj.toString());
     * msg.setFormula(setting.getString("formula")); //
     * 此处通过引用传递将简化之后的计算公式回传newFormula AnalysisResult result =
     * CommandInterpreter.commandAnalysis(setting, rule, indDto); Map<String,
     * RuleDto> subRuleMap = result.getSubRuleMap(); String simpleFormula =
     * result.getSimpleFormula(); Set<Entry<String, RuleDto>> subRule =
     * subRuleMap.entrySet(); Map<String, SubRuleReport> subValidateResult = new
     * HashMap<>(); for (Entry<String, RuleDto> entry : subRule) {
     * msg.setSubKey(entry.getKey()); NmsCaller subCaller = new NmsCaller();
     * CopyBeanUtils.copyProperties(callData, subCaller, "rule");
     * subCaller.setRule(entry.getValue()); CompositionSupport supportor =
     * getSubStrategySupportor(subCaller); SubRuleReport subReport =
     * supportor.support4Holistic(); subValidateResult.put(entry.getKey(),
     * subReport); } boolean valiStatus = ruleMatch(subValidateResult,
     * simpleFormula); <<<<<<< HEAD alertStatus = alertStatus || valiStatus;
     * indStatus = updateIndStatusVal(indStatus, valiStatus ? hit : not_hit);
     * ValidateAlertInfo alert = dealWithValidateResult(setting, valiStatus,
     * rule.getCompareType(), subValidateResult, msg, simpleFormula,null); =======
     * if (valiStatus) { alertStatus = true; } ValidateAlertInfo alert =
     * dealWithValidateResult(setting, valiStatus, rule.getCompareType(),
     * subValidateResult, msg, simpleFormula); >>>>>>> beta_3.0.3_t7.final
     * alertInfoList.add(alert); } NmsReport report = new NmsReport();
     * report.setIndStatus(alertStatus ? hit : not_hit);
     * report.setAlertStatus(alertStatus); report.setAlertList(alertInfoList);
     * return report; }
     */

    /**
     * 组合策略不按照资源告警(整体的)校验流程校验告警
     */
    @Override
    public NmsReport holisticVerifyProcess() {
        return modularVerifyProcess();
        /*
         * RuleDto rule = callData.getRule(); ValidateMsg msg = getMsg(); List<String>
         * componentIds = getComponentIds(rule);
         * msg.setComponentId(componentIds.stream().distinct().collect(Collectors.
         * joining(","))); IndicatorTableDto indDto = callData.getIndicator(); boolean
         * alertStatus = false; List<ValidateAlertInfo> alertInfoList = new
         * ArrayList<>(); for (Object obj : JSON.parseArray(rule.getSettings())) {
         * JSONObject setting = JSON.parseObject(obj.toString());
         * msg.setFormula(setting.getString("formula")); //
         * 此处通过引用传递将简化之后的计算公式回传newFormula AnalysisResult result =
         * CommandInterpreter.commandAnalysis(setting, rule, indDto); Map<String,
         * RuleDto> subRuleMap = result.getSubRuleMap(); String simpleFormula =
         * result.getSimpleFormula(); Set<Entry<String, RuleDto>> subRule =
         * subRuleMap.entrySet(); Map<String, SubRuleReport> subValidateResult =
         * compositionVerifyProcess(subRule, simpleFormula, msg); boolean valiStatus =
         * false; for (Entry<String, SubRuleReport> entry :
         * subValidateResult.entrySet()) { if (entry.getValue().getAlertStatus()) {
         * valiStatus = true; alertStatus = true; } } ValidateAlertInfo alert =
         * dealWithValidateResult(setting, valiStatus, rule.getCompareType(),
         * subValidateResult, msg, simpleFormula); alertInfoList.add(alert); } NmsReport
         * report = new NmsReport(); report.setIndStatus(alertStatus ? hit : not_hit);
         * report.setAlertStatus(alertStatus); report.setAlertList(alertInfoList);
         * return report;
         */
    }

    public Map<String, SubRuleReport> compositionVerifyProcess(Set<Entry<String, RuleDto>> subRule,
        String simpleFormula, ValidateMsg msg) {
        JSONArray array = callData.getIndValue();
        RuleDto rule = callData.getRule();
        IndicatorTableDto indicator = callData.getIndicator();
        boolean isComponent = "LIST".equals(indicator.getIndicatorType())
                && (indicator.getNoKey() == null || !indicator.getNoKey());
        JSONArray historyArray = callData.getHistoryValue();
        List<String> componentIds = getComponentIds(rule);
        Map<String, SubRuleReport> subValidateResult = new HashMap<>();
        for (Object dataObj : array) {
            JSONObject value = null;
            try {
                value = JSONObject.parseObject(dataObj.toString());// 当前检测数据
            } catch (Exception e) {
                LOG.error("", e);
                continue;
            }
            String currentComponentId = "";
            if (isComponent) {
                try {
                    value = JSONObject.parseObject(dataObj.toString());// 当前检测数据
                    currentComponentId = value.containsKey("identifier") ? value.getString("identifier") : currentComponentId;
                } catch (Exception e) {
                    LOG.error("MVEL.evalToString error. -> " + indicator.getComponentNameFormula() + ", " + dataObj, e);
                }
                if (!validateEnable(currentComponentId, componentIds)) {// 校验使能
                    continue;
                }
            }
            Map<String, Boolean> subValidateOne = new HashMap<>();
            SubRuleReport srr = new SubRuleReport();
            String subAlertContent = "【";
            String key = "";
            for (Entry<String, RuleDto> entry : subRule) {
                key += entry.getKey() + ",";
                RuleDto splitRule = entry.getValue();
                NmsCaller subCaller = new NmsCaller();
                CopyBeanUtils.copyProperties(callData, subCaller, "rule");
                subCaller.setRule(splitRule);
                CompositionSupport supportor = getSubStrategySupportor(subCaller);
                JSONArray subRuleSettings = JSONArray.parseArray(entry.getValue().getSettings());
                JSONObject subRuleSetting = (subRuleSettings == null || subRuleSettings.isEmpty()) ? new JSONObject() : subRuleSettings
                    .getJSONObject(0);
                boolean warning = supportor.verifierUnit(value, currentComponentId, splitRule, subRuleSetting,
                    historyArray, msg, false);
                subValidateOne.put(entry.getKey(), warning);
                String currentValue = getCurrentValueFromCollectData(value, splitRule.getFieldName());
                if (StringUtils.isNotBlank(currentValue)) {
                    subAlertContent += splitRule.getFieldText() + "=" + currentValue + ",";
                }
            }
            // 校验当前部件是否满足策略告警条件
            boolean validStatus = ruleMatchResult(subValidateOne, simpleFormula);
            if (subAlertContent.endsWith(",")) {
                subAlertContent = subAlertContent.substring(0, subAlertContent.lastIndexOf(","));
            }
            subAlertContent = subAlertContent + "】";
            if (key.endsWith(",")) {
                key = key.substring(0, key.lastIndexOf(","));
            }
            srr.setAlertStatus(validStatus);
            srr.setSubAlertContent(subAlertContent.length() > 2 && validStatus ? subAlertContent : null);
            subValidateResult.put(dataObj.toString() + "_" + key, srr);
        }
        return subValidateResult;
    }

    public boolean ruleMatchResult(Map<String, Boolean> subStrategyMap, String simpleFormula) {
        Map<String, Object> param = new HashMap<>();
        for (Entry<String, Boolean> entry : subStrategyMap.entrySet()) {
            param.put(entry.getKey(), entry.getValue());
        }
        boolean result = (boolean) MVEL.eval(simpleFormula, param);
        return result;
    }

    private CompositionSupport getSubStrategySupportor(NmsCaller subCaller) {
        CompositionSupport subHandler = null;
        switch (subCaller.getRule().getCompareType()) {
        case string:
            subHandler = new StringStrategyHandler(subCaller);
            break;
        case sum:
            subHandler = new SumStrategyHandler(subCaller);
            break;
        case exists:
            subHandler = new ExistStrategyHandler(subCaller);
            break;
        case history:
            subHandler = new HistoryStrategyHandler(subCaller);
            break;
        case range:
            subHandler = new RangeStrategyHandler(subCaller);
        case change:
            subHandler = new ListStrategyHandler(subCaller);
            break;
        default:
            break;
        }

        return subHandler;
    }

    public NmsReport modularVerifyProcess() {
        RuleDto rule = callData.getRule();
        JSONArray array = callData.getIndValue();
        IndicatorTableDto indDto = callData.getIndicator();
        ValidateMsg msg = getMsg();
        List<String> componentIds = getComponentIds(rule);
        // msg.setComponentId(componentIds.stream().distinct().collect(Collectors.joining(",")));
        List<ValidateAlertInfo> alertInfoList = new ArrayList<>();
        boolean alertStatus = false;
        for (Object obj : JSON.parseArray(rule.getSettings())) {
            JSONObject setting = JSON.parseObject(obj.toString());
            msg.setFormula(setting.getString("formula"));
            // 此处通过引用传递将简化之后的计算公式回传newFormula
            AnalysisResult result = CommandInterpreter.commandAnalysis(setting, rule, indDto);
            Map<String, RuleDto> subRuleMap = result.getSubRuleMap();
            String simpleFormula = result.getSimpleFormula();
            Set<Entry<String, RuleDto>> subRule = subRuleMap.entrySet();
            for (Object o : array) {
                Map<String, SubRuleReport> subValidateResult = new HashMap<>();
                JSONObject compData = JSONObject.parseObject(o.toString());
                msg.setComponentName("");
                String componentId = compData.getString("identifier");
                if (validateEnable(componentId, componentIds)) {// 检测该部件是否需要进行策略校验
                    msg.setComponentId(componentId);
                } else {
                    continue;
                }
                JSONArray indValue = new JSONArray();
                indValue.add(compData);
                for (Entry<String, RuleDto> entry : subRule) {
                    msg.setSubKey(entry.getKey());
                    NmsCaller subCaller = new NmsCaller();
                    CopyBeanUtils.copyProperties(callData, subCaller, "rule");
                    subCaller.setIndValue(indValue);
                    subCaller.setRule(entry.getValue());
                    CompositionSupport supportor = getSubStrategySupportor(subCaller);
                    SubRuleReport subReport = supportor.support4Modular(compData);
                    subValidateResult.put(entry.getKey(), subReport);
                }
                boolean valiStatus = ruleMatch(subValidateResult, simpleFormula);
                if (valiStatus) {
                    alertStatus = true;
                }
                ValidateAlertInfo alert = dealWithValidateResult(setting, valiStatus, rule.getCompareType(),
                    subValidateResult, msg, simpleFormula, indValue);
                alertInfoList.add(alert);
            }
        }
        NmsReport report = new NmsReport();
        report.setIndStatus(alertStatus ? hit : not_hit);
        report.setAlertStatus(alertStatus);
        report.setAlertList(alertInfoList);
        return report;
    }

    public ValidateAlertInfo dealWithValidateResult(JSONObject setting, boolean valiStatus, CompareType compareType,
        Map<String, SubRuleReport> subValidateResult, ValidateMsg msg, String newFormula, JSONArray dataRecords) {
        Long eventId = setting.getLong("handler");
        int level = setting.getIntValue("level");
        long flap = setting.getLongValue("flap");
        String alertCode = "";
        if (BaseNeClass.virtualization.equals(msg.getNe().getNeClass().getBaseNeClass())) {// 按部件告警
            alertCode = createAlertCode(setting, msg);
        } else {
            alertCode = createAlertCode(setting, msg);
        }
        String currentValue = "";
        for (Entry<String, SubRuleReport> entry : subValidateResult.entrySet()) {
            SubRuleReport subReport = entry.getValue();
            if (StringUtils.isNotBlank(subReport.getSubAlertContent())) {
                currentValue += subReport.getSubAlertContent();
            }
        }
        if (currentValue.endsWith(",")) {
            currentValue = currentValue.substring(0, currentValue.lastIndexOf(","));
        }
        msg.setCurrentValue(currentValue);
        msg.setRange(msg.getFormula());
        ValidateAlertInfo alert = new ValidateAlertInfo();
        alert.setEventId(eventId);
        alert.setLevel(level);
        alert.setAlertCode(alertCode);
        alert.setAlertBrief(createAlertBrief(msg, setting.getString("template"), valiStatus));
        alert.setObjectId(msg.getNe().getId());
        alert.setSource(AlertOrigin.POLLING.toString());
        msg.setComponentName("");
        ValidateMsg sendMsg = new ValidateMsg();
        CopyBeanUtils.copyProperties(msg, sendMsg);
        alert.setMsg(sendMsg);
        alert.setFlap(flap);
        alert.setType(valiStatus ? "alert" : "recover");
        return alert;
    }
}